﻿/* 
This file is part of Ingo Karstein's SharePoint PowerShell Timer Jobs project

**Do not remove this comment**

Please see the project homepage at CodePlex:
  http://sppowershelltimerjob.codeplex.com/

Please see my blog:
  http://ikarstein.wordpress.com

Licence: GPLv2
    Ingo Karstein's SharePoint PowerShell Timer Jobs
    Copyright (C) 2011  Ingo Karstein, ikarstein@hotmail.com

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

/* 
This file is part of Ingo Karstein's SharePoint PowerShell Timer Jobs project

**Do not remove this comment**

Please see the project homepage at CodePlex:
  http://sppowershelltimerjob.codeplex.com/

Please see my blog:
  http://ikarstein.wordpress.com

Licence: GPLv2
    Ingo Karstein's SharePoint PowerShell Timer Jobs
    Copyright (C) 2011  Ingo Karstein, ikarstein@hotmail.com

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

using System;
using System.Linq;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.Administration;
using System.Collections.Generic;

namespace ik.SharePoint2010.SPPowerShellTimerJob.Layouts.SPPowerShellTimerJob
{
    public partial class ManageJobs : LayoutsPageBase
    {
        private SortedList<Guid, string> jobs = new SortedList<Guid, string>();
        private SortedList<Guid, string> webapps = new SortedList<Guid, string>();
        private SortedList<Guid, string> services = new SortedList<Guid, string>();
        private SortedList<Guid, string> servers = new SortedList<Guid, string>();

        private bool typeChanged = false;
        private bool serviceChanged = false;
        private bool webappChanged = false;
        private bool nameChanged = false;
        private bool enabledChanged = false;

        private Guid currentJobGuid = Guid.Empty;
        private SPJobDefinition currentJob = null;

        private SPService timerService = null;

        protected const string scripttemplate = "<# PowerShell Job created by Ingo Karstein's SharePoint PowerShell Timer Job\r\n\r\nFollow the project on Codeplex: http://sppowershelltimerjob.codeplex.com/ #>\n\r";

        private void CheckServices()
        {
            foreach( SPService s in SPFarm.Local.Services )
            {
                CheckService(s);
            }
        }

        public SPJobDefinition CurrentJob
        {
            get
            {
                return currentJob;
            }
        }

        private void CheckServers()
        {
            foreach( SPServer s in SPFarm.Local.Servers )
            {
                servers.Add(s.Id, s.Name);
            }
        }

        private void CheckService(SPService service)
        {
            services.Add(service.Id, service.TypeName);
            foreach( SPJobDefinition job in service.JobDefinitions )
            {
                CheckJobDefinition(job);
            }

            if( service is SPWebService )
            {
                SPWebService webservice = service as SPWebService;
                foreach( SPWebApplication webapp in webservice.WebApplications )
                {
                    CheckWebApplication(webapp);
                }
            }
        }

        private void CheckWebApplication(SPWebApplication webapp)
        {
            webapps.Add(webapp.Id, webapp.DisplayName);
            foreach( SPJobDefinition job in webapp.JobDefinitions )
            {
                CheckJobDefinition(job);
            }
        }

        private void CheckJobDefinition(SPJobDefinition jobdef)
        {
            if( jobdef is SPPowerShellJobDefinition )
            {
                jobs.Add(jobdef.Id, jobdef.Title);
            }
        }

        private SPService FindService(string name)
        {
            foreach( SPService s in SPFarm.Local.Services )
            {
                if( s.TypeName == name )
                    return s;
            }
            return null;
        }
        private SPServer FindServer(string name)
        {
            foreach( SPServer s in SPFarm.Local.Servers )
            {
                if( s.Name == name )
                    return s;
            }
            return null;
        }
        private SPServer FindServer(Guid id)
        {
            foreach( SPServer s in SPFarm.Local.Servers )
            {
                if( Guid.Equals(s.Id, id) )
                    return s;
            }
            return null;
        }
        private SPJobDefinition FindJobDef(string name)
        {
            foreach( SPService s in SPFarm.Local.Services )
            {
                SPJobDefinition jobdef = FindJobDefInService(s, name);
                if( jobdef != null )
                    return jobdef;
            }

            return null;
        }
        protected SPJobDefinition FindJobDef(Guid id)
        {
            foreach( SPService s in SPFarm.Local.Services )
            {
                SPJobDefinition jobdef = FindJobDefInService(s, id);
                if( jobdef != null )
                    return jobdef;
            }

            return null;
        }

        private SPJobDefinition FindJobDefInService(SPService service, string name)
        {
            var w = ( from s in service.JobDefinitions.Cast<SPJobDefinition>()
                      where string.Equals(s.Name, name, StringComparison.InvariantCultureIgnoreCase)
                      select s ).FirstOrDefault();

            if( w != null )
                return w;

            if( service is SPWebService )
            {
                SPWebService webservice = service as SPWebService;
                foreach( SPWebApplication webapp in webservice.WebApplications )
                {
                    SPJobDefinition jobdef = FindJobDefInWebApp(webapp, name);
                    if( jobdef != null )
                        return jobdef;
                }
            }

            return null;
        }

        private SPJobDefinition FindJobDefInService(SPService service, Guid id)
        {
            var w = ( from s in service.JobDefinitions.Cast<SPJobDefinition>()
                      where Guid.Equals(s.Id, id)
                      select s ).FirstOrDefault();

            if( w != null )
                return w;

            if( service is SPWebService )
            {
                SPWebService webservice = service as SPWebService;
                foreach( SPWebApplication webapp in webservice.WebApplications )
                {
                    SPJobDefinition jobdef = FindJobDefInWebApp(webapp, id);
                    if( jobdef != null )
                        return jobdef;
                }
            }

            return null;
        }

        private SPJobDefinition FindJobDefInWebApp(SPWebApplication webapp, string name)
        {
            return ( from s in webapp.JobDefinitions.Cast<SPJobDefinition>()
                     where string.Equals(s.Name, name, StringComparison.InvariantCultureIgnoreCase)
                     select s ).FirstOrDefault();
        }

        private SPJobDefinition FindJobDefInWebApp(SPWebApplication webapp, Guid id)
        {
            return ( from s in webapp.JobDefinitions.Cast<SPJobDefinition>()
                     where Guid.Equals(s.Id, id)
                     select s ).FirstOrDefault();
        }

        private SPWebApplication FindWebApp(string name)
        {
            return ( from s in SPFarm.Local.Services.GetValue<SPWebService>().WebApplications.Cast<SPWebApplication>()
                     where string.Equals(s.Name, name, StringComparison.InvariantCultureIgnoreCase)
                     select s ).FirstOrDefault();
        }

        private SPWebApplication FindWebApp(Guid id)
        {
            return ( from s in SPFarm.Local.Services.GetValue<SPWebService>().WebApplications.Cast<SPWebApplication>()
                     where Guid.Equals(s.Id, id)
                     select s ).FirstOrDefault();
        }

        private void FillinData()
        {
            if( dpdTimerjobs.SelectedIndex == 0 )
            {
                btnAddOrUpdate.Text = "Add";
                btnAddOrUpdate.Enabled = true;
                btnDelete.Enabled = false;
                rType.SelectedIndex = -1;
                dpdWebApp.Enabled = false;

                //if( rType.SelectedIndex < 0 )
                //{
                //    dpdServices.Enabled = false;
                //    dpdWebApp.Enabled = false;
                //}
                //
                //if( rType.SelectedIndex < 0 || string.IsNullOrEmpty(JobName.Text) )
                //    btnAddOrUpdate.Enabled = false;
            }
            else
            {
                btnAddOrUpdate.Text = "Update";
                btnDelete.Enabled = true;
            }

            if( rType.SelectedIndex == 0 )
            {
                dpdServices.Enabled = true;
                dpdWebApp.Enabled = false;
            }
            else if( rType.SelectedIndex == 1 )
            {
                dpdServices.Enabled = false;
                dpdWebApp.Enabled = true;
            }

        }

        private void CollectData()
        {
            jobs = new SortedList<Guid, string>();
            services = new SortedList<Guid, string>();
            webapps = new SortedList<Guid, string>();
            servers = new SortedList<Guid, string>();

            CheckServices();
            CheckServers();

            dpdTimerjobs.Items.Clear();
            dpdServices.Items.Clear();
            dpdWebApp.Items.Clear();
            dpdServer.Items.Clear();

            dpdTimerjobs.Items.Add(new System.Web.UI.WebControls.ListItem("<new>", Guid.Empty.ToString()));
            dpdServices.Items.Add(new System.Web.UI.WebControls.ListItem("<select a service>", Guid.Empty.ToString()));
            dpdWebApp.Items.Add(new System.Web.UI.WebControls.ListItem("<select a web app>", Guid.Empty.ToString()));
            dpdServer.Items.Add(new System.Web.UI.WebControls.ListItem("<all servers>", Guid.Empty.ToString()));

            foreach( var jd in jobs )
            {
                dpdTimerjobs.Items.Add(new System.Web.UI.WebControls.ListItem(jd.Value, jd.Key.ToString()));
            }

            foreach( var s in services )
            {
                dpdServices.Items.Add(new System.Web.UI.WebControls.ListItem(s.Value, s.Key.ToString()));
            }

            foreach( var w in webapps )
            {
                dpdWebApp.Items.Add(new System.Web.UI.WebControls.ListItem(w.Value, w.Key.ToString()));
            }

            foreach( var s in servers )
            {
                dpdServer.Items.Add(new System.Web.UI.WebControls.ListItem(s.Value, s.Key.ToString()));
            }
        }

        protected override void LoadViewState(object savedState)
        {
            base.LoadViewState(savedState);

            jobs = ViewState["jobs"] as SortedList<Guid, string>;
            services = ViewState["services"] as SortedList<Guid, string>;
            webapps = ViewState["webapps"] as SortedList<Guid, string>;
            servers = ViewState["servers"] as SortedList<Guid, string>;
        }

        protected override object SaveViewState()
        {
            ViewState["jobs"] = jobs;
            ViewState["services"] = services;
            ViewState["webapps"] = webapps;
            ViewState["servers"] = servers;

            return base.SaveViewState();
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            FormServices.Visible = false;
            FormWebApp.Visible = false;
            FormType.Visible = false;

            btnAddOrUpdate.Click += new EventHandler(btnAddOrUpdate_Click);
            btnDelete.Click += new EventHandler(btnDelete_Click);
            refresh.Click += new EventHandler(refresh_Click);

            dpdTimerjobs.SelectedIndexChanged += new EventHandler(dpdTimerjobs_SelectedIndexChanged);
            dpdTimerjobs.AutoPostBack = true;
            dpdTimerjobs.EnableViewState = true;

            JobName.TextChanged += new EventHandler(JobName_TextChanged);
            JobName.AutoPostBack = false;
            JobName.EnableViewState = true;

            cbActived.CheckedChanged += new EventHandler(cbActived_CheckedChanged);
            cbActived.AutoPostBack = false;
            cbActived.EnableViewState = true;

            rType.SelectedIndexChanged += new EventHandler(rType_SelectedIndexChanged);
            rType.AutoPostBack = true;
            rType.EnableViewState = true;

            dpdServices.SelectedIndexChanged += new EventHandler(dpdServices_SelectedIndexChanged);
            dpdServices.AutoPostBack = true;
            dpdServices.EnableViewState = true;

            dpdWebApp.SelectedIndexChanged += new EventHandler(dpdWebApp_SelectedIndexChanged);
            dpdWebApp.AutoPostBack = true;
            dpdWebApp.EnableViewState = true;

            //timerService = SPFarm.Local.Services.GetValue<SPTimerService>();
            foreach( SPService s in SPFarm.Local.Services )
            {
                if( s is SPTimerService )
                {
                    timerService = s;
                    break;
                }
            }

            if( dpdTimerjobs.SelectedIndex >= 0 )
            {
                currentJobGuid = new Guid(dpdTimerjobs.SelectedValue);
            }
            else
                currentJobGuid = Guid.Empty;

            if( !Guid.Equals(currentJobGuid, Guid.Empty) )
                currentJob = FindJobDef(currentJobGuid);
            else
                currentJob = null;

            if( currentJob != null )
            {
                btnEdit.Enabled = true;
                txtPowerShellScript.Text = (string)currentJob.Properties["PSScript"];
                btnEdit.OnClientClick = "javascript: ikShowEditScriptDlg();return false;";
            }
            else
            {
                btnEdit.Enabled = false;

                if( !IsPostBack )
                {

                    JobName.Text = "";
                    rType.SelectedIndex = -1;
                    cbActived.Checked = false;
                    cbRunAsJob.Checked = true;
                    dpdServices.SelectedIndex = 0;
                    dpdWebApp.SelectedIndex = 0;

                    var d = new SPDailySchedule();
                    d.BeginHour = 0;
                    d.BeginMinute = 0;
                    d.BeginSecond = 0;
                    d.EndHour = 0;
                    d.EndMinute = 1;
                    d.EndSecond = 59;
                    ( (Microsoft.SharePoint.WebControls.SchedulePicker)SchedulePicker ).Schedule = d;
                    txtPowerShellScript.Text = scripttemplate;
                }
            }

            if( !IsPostBack )
            {
                CollectData();

                dpdTimerjobs.SelectedIndex = 0;

                FillinData();
            }
        }

        void refresh_Click(object sender, EventArgs e)
        {
            
        }

        void btnDelete_Click(object sender, EventArgs e)
        {
            SPJobDefinition oldJobDef = currentJob;

            if( currentJob != null )
            {
                currentJob.Delete();
                CollectData();
                FillinData();
                dpdTimerjobs.SelectedIndex = 0;
            }
        }

        protected void ValidateJobName(object source, System.Web.UI.WebControls.ServerValidateEventArgs args)
        {
            if( !nameChanged )
            {
                args.IsValid = true;
                return;
            }

            if( args.Value.Length >= 10 )
                args.IsValid = true;
            else
                args.IsValid = false;
        }

        void dpdWebApp_SelectedIndexChanged(object sender, EventArgs e)
        {
            webappChanged = true;

            FillinData();
        }

        void dpdServices_SelectedIndexChanged(object sender, EventArgs e)
        {
            serviceChanged = true;

            FillinData();
        }

        void cbActived_CheckedChanged(object sender, EventArgs e)
        {
            enabledChanged = true;

            FillinData();
        }

        void JobName_TextChanged(object sender, EventArgs e)
        {
            nameChanged = true;
            FillinData();
        }

        void dpdTimerjobs_SelectedIndexChanged(object sender, EventArgs e)
        {
            typeChanged = false;
            serviceChanged = false;
            webappChanged = false;
            nameChanged = false;
            enabledChanged = false;

            if( dpdTimerjobs.SelectedIndex == 0 )
            {
                JobName.Text = "";
                rType.SelectedIndex = -1;
                cbActived.Checked = false;
                cbRunAsJob.Checked = true;
                dpdServices.SelectedIndex = 0;
                dpdWebApp.SelectedIndex = 0;

                var d = new SPDailySchedule();
                d.BeginHour = 0;
                d.BeginMinute = 0;
                d.BeginSecond = 0;
                d.EndHour = 0;
                d.EndMinute = 1;
                d.EndSecond = 59;
                ( (Microsoft.SharePoint.WebControls.SchedulePicker)SchedulePicker ).Schedule = d;
                txtPowerShellScript.Text = scripttemplate;
            }
            else
            {
                JobName.Text = currentJob.DisplayName;
                SPSchedule s = null;
                if( CurrentJob.Schedule is SPDailySchedule )
                {
                    var s1 = new SPDailySchedule
                    {
                        BeginHour = ( (SPDailySchedule)currentJob.Schedule ).BeginHour,
                        BeginMinute = ( (SPDailySchedule)currentJob.Schedule ).BeginMinute,
                        BeginSecond = ( (SPDailySchedule)currentJob.Schedule ).BeginSecond,
                        EndHour = ( (SPDailySchedule)currentJob.Schedule ).EndHour,
                        EndMinute = ( (SPDailySchedule)currentJob.Schedule ).EndMinute,
                        EndSecond = ( (SPDailySchedule)currentJob.Schedule ).EndSecond
                    };
                    s = s1;
                }
                else if( CurrentJob.Schedule is SPMinuteSchedule )
                {
                    var s1 = new SPMinuteSchedule
                    {
                        BeginSecond = ( (SPMinuteSchedule)currentJob.Schedule ).BeginSecond,
                        EndSecond= ( (SPMinuteSchedule)currentJob.Schedule ).EndSecond,
                        Interval = ( (SPMinuteSchedule)currentJob.Schedule ).Interval
                    };
                    s = s1;
                }
                else if( CurrentJob.Schedule is SPHourlySchedule )
                {
                    var s1 = new SPHourlySchedule
                    {
                        BeginMinute = ( (SPHourlySchedule)currentJob.Schedule ).BeginMinute,
                        EndMinute = ( (SPHourlySchedule)currentJob.Schedule ).EndMinute
                    };
                    s = s1;
                }
                else if( CurrentJob.Schedule is SPWeeklySchedule )
                {
                    var s1 = new SPWeeklySchedule
                    {
                        BeginHour = ( (SPWeeklySchedule)currentJob.Schedule ).BeginHour,
                        BeginMinute = ( (SPWeeklySchedule)currentJob.Schedule ).BeginMinute,
                        BeginSecond = ( (SPWeeklySchedule)currentJob.Schedule ).BeginSecond,
                        EndHour = ( (SPWeeklySchedule)currentJob.Schedule ).EndHour,
                        EndMinute = ( (SPWeeklySchedule)currentJob.Schedule ).EndMinute,
                        EndSecond = ( (SPWeeklySchedule)currentJob.Schedule ).EndSecond,
                        BeginDayOfWeek = ( (SPWeeklySchedule)currentJob.Schedule ).BeginDayOfWeek,
                        EndDayOfWeek = ( (SPWeeklySchedule)currentJob.Schedule ).EndDayOfWeek
                    };
                    s = s1;
                }
                else if( CurrentJob.Schedule is SPMonthlyByDaySchedule )
                {
                    var s1 = new SPMonthlyByDaySchedule
                    {
                        BeginHour = ( (SPMonthlyByDaySchedule)currentJob.Schedule ).BeginHour,
                        BeginMinute = ( (SPMonthlyByDaySchedule)currentJob.Schedule ).BeginMinute,
                        BeginSecond = ( (SPMonthlyByDaySchedule)currentJob.Schedule ).BeginSecond,
                        BeginWeek = ( (SPMonthlyByDaySchedule)currentJob.Schedule ).BeginWeek,
                        BeginDay = ( (SPMonthlyByDaySchedule)currentJob.Schedule ).BeginDay
                    };
                    s = s1;
                }
                else if( CurrentJob.Schedule is SPMonthlySchedule )
                {
                    var s1 = new SPMonthlySchedule
                    {
                        BeginHour = ( (SPMonthlySchedule)currentJob.Schedule ).BeginHour,
                        BeginMinute = ( (SPMonthlySchedule)currentJob.Schedule ).BeginMinute,
                        BeginSecond = ( (SPMonthlySchedule)currentJob.Schedule ).BeginSecond,
                        EndHour = ( (SPMonthlySchedule)currentJob.Schedule ).EndHour,
                        EndMinute = ( (SPMonthlySchedule)currentJob.Schedule ).EndMinute,
                        EndSecond = ( (SPMonthlySchedule)currentJob.Schedule ).EndSecond,
                        BeginDay = ( (SPMonthlySchedule)currentJob.Schedule ).BeginDay,
                        EndDay = ( (SPMonthlySchedule)currentJob.Schedule ).EndDay,
                    };
                    s = s1;
                }
                ( (Microsoft.SharePoint.WebControls.SchedulePicker)SchedulePicker ).Schedule = s;
                cbActived.Checked = !currentJob.IsDisabled;
                cbRunAsJob.Checked = ( ( currentJob.LockType & SPJobLockType.Job ) != 0 );
                txtPowerShellScript.Text = currentJob.Properties["PSScript"] as string;
            }

            FillinData();
        }

        void rType_SelectedIndexChanged(object sender, EventArgs e)
        {
            typeChanged = true;

            FillinData();
        }

        void btnAddOrUpdate_Click(object sender, System.EventArgs e)
        {
            SPServer server = null;
            if( dpdServer.SelectedIndex > 0 )
                server = FindServer(new Guid(dpdServer.SelectedValue));

            SPJobDefinition oldJobDef = currentJob;

            string psscript = scripttemplate;
            if( currentJob != null )
            {

                if( string.Equals(currentJob.DisplayName, JobName.Text) &&
                    SPServer.Equals(currentJob.Server, server) &&
                    bool.Equals(currentJob.LockType, ( cbRunAsJob.Checked ? SPJobLockType.Job : SPJobLockType.None )) )
                {
                    currentJob.Schedule = ( (Microsoft.SharePoint.WebControls.SchedulePicker)SchedulePicker ).Schedule;
                    currentJob.IsDisabled = !cbActived.Checked;

                    currentJob.Update();

                    FillinData();
                    return;
                }

                if( nameChanged )
                {
                    if( !string.Equals(currentJob.DisplayName, JobName.Text) )
                    {
                        var x = FindJobDef(JobName.Text);
                        if( x != null )
                        {
                            JobNameValidator.IsValid = false;
                            return;
                        }

                        JobNameValidator.IsValid = true;
                    }
                }

                txtPowerShellScript.Text = currentJob.Properties["PSScript"] as string;
                psscript = currentJob.Properties["PSScript"] as string;
                oldJobDef.IsDisabled = true;
                oldJobDef.Update();
            }

            bool ok = false;
            try
            {
                if( oldJobDef == null )
                {
                    var x = FindJobDef(JobName.Text);
                    if( x != null )
                    {
                        JobNameValidator.IsValid = false;
                        return;
                    }
                }

                JobNameValidator.IsValid = true;

                SPPowerShellJobDefinition psjobdef = new SPPowerShellJobDefinition(JobName.Text, timerService, server, ( cbRunAsJob.Checked ? SPJobLockType.Job : SPJobLockType.None ));
                psjobdef.Schedule = ( (Microsoft.SharePoint.WebControls.SchedulePicker)SchedulePicker ).Schedule;
                psjobdef.IsDisabled = !cbActived.Checked;
                psjobdef.Properties["PSScript"] = psscript;
                txtPowerShellScript.Text = psscript;
                psjobdef.Update();

                ok = true;

                if( ok && oldJobDef != null )
                {
                    oldJobDef.Delete();
                    oldJobDef = null;
                }

                CollectData();

                if( psjobdef != null )
                {
                    int i = 0;
                    while( i < dpdTimerjobs.Items.Count )
                    {
                        if( Guid.Equals(psjobdef.Id, new Guid(dpdTimerjobs.Items[i].Value)) )
                        {
                            dpdTimerjobs.SelectedIndex = i;
                            break;
                        }

                        i++;
                    }
                }

                currentJob = psjobdef;
                currentJobGuid = currentJob.Id;

                if( currentJob != null )
                {
                    btnEdit.Enabled = true;
                    btnEdit.OnClientClick = "javascript: ikShowEditScriptDlg();return false;";
                }

                nameChanged = false;

                FillinData();
            }
            finally
            {
               
            }
        }
    }
}
